package com.example.demo.warn.manager;

import cn.hutool.core.map.MapUtil;
import com.example.demo.warn.config.WarnConfiguration;
import com.example.demo.warn.mapper.WarnMapper;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.LineString;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKTReader;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 预警设备管理
 * 用于查询设备的坐标数据
 *
 * @author yuanz
 * @date 2024/06/06
 */
@Component
public class WarnEquipManager {

    @Resource
    private WarnMapper warnMapper;

    @Resource
    private WarnConfiguration warnConfiguration;

    private static final String KEY_CONCAT_STR = "-";

    /**
     * 存储设备的坐标信息
     */
    private Map<String, Object> equipPointMap = new HashMap<>();

    /**
     * 存储设备间的时间信息
     */
    private Map<String, long[]> equipTimesMap = new HashMap<>();

//    @PostConstruct
    public void init() {
        queryEquipBasicInfoList();
    }

    /**
     * 获取设备的基础信息
     */
    private void queryEquipBasicInfoList() {
        List<Map<String, Object>> equipPointInfoList = warnMapper.queryEquipBasicInfoList();
        equipPointInfoList.forEach(map -> {
            equipPointMap.put(MapUtil.getStr(map, "id"), MapUtil.getStr(map, "point"));
        });

    }

    /**
     * 获取两个设备的通过时间
     *
     * @param equipIdFrom 设备ID
     * @param equipIdTo   设备ID
     * @return 通过时间
     */
    public long[] getTimes(String equipIdFrom, String equipIdTo) {
        long[] times;
        String twoEquipKey = equipIdFrom + KEY_CONCAT_STR + equipIdTo;
        if (equipTimesMap.containsKey(twoEquipKey)) {
            times = equipTimesMap.get(twoEquipKey);
        } else {
            String speedAndTime = warnConfiguration.speedAndTime;
            String pointFrom = String.valueOf(equipPointMap.get(equipIdFrom));
            String pointTo = String.valueOf(equipPointMap.get(equipIdTo));
            double length = getPointDistance(pointFrom, pointTo);
            times = getTime(length, speedAndTime);
            equipPointMap.put(twoEquipKey, times);
            equipPointMap.put(equipIdTo + KEY_CONCAT_STR + equipIdFrom, times);
        }
        return times;
    }

    /**
     * 计算两点间的距离
     *
     * @param pointA 点A
     * @param pointB 点B
     * @return 距离
     */
    private double getLength(String pointA, String pointB) {
        GeometryFactory geometryFactory = new GeometryFactory();
        WKTReader wktReader = new WKTReader(geometryFactory);
        String subway = "LINESTRING(" + pointA + "," + pointB + ")";
        LineString lineString = null;
        try {
            lineString = (LineString) wktReader.read(subway);
            System.out.println("LineString: " + lineString + "; LineLength: " + (lineString.getLength() * 111.265));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        assert lineString != null;
        return lineString.getLength() * 100000;
    }

    /**
     * 计算两点之间的距离（忽略弧度）
     *
     * @param pointOne   点一
     * @param pointOther 另一个点
     * @return 两点直接的距离
     */
    private static double getPointDistance(String pointOne, String pointOther) {
        String[] pointOneArr = pointOne.split(" ");
        String[] pointOtherArr = pointOther.split(" ");
        return Math.sqrt(
                Math.abs(
                        (Double.parseDouble(pointOneArr[0]) - Double.parseDouble(pointOtherArr[0]))
                                * (Double.parseDouble(pointOneArr[0]) - Double.parseDouble(pointOtherArr[0]))
                                + (Double.parseDouble(pointOneArr[1]) - Double.parseDouble(pointOtherArr[1]))
                                * (Double.parseDouble(pointOneArr[1]) - Double.parseDouble(pointOtherArr[1]))
                )
        );
    }

    /**
     * 根据距离、速度和时间参数计算窗口时间
     *
     * @param length       距离
     * @param speedAndTime 速度
     * @return 窗口时间
     */
    private long[] getTime(double length, String speedAndTime) {
        long[] times = new long[3];
        String[] speedAndBufferTimeArr = speedAndTime.split(",");
        long footSpeed = Long.parseLong(speedAndBufferTimeArr[0]);
        long carSpeed = Long.parseLong(speedAndBufferTimeArr[1]);
        long windowTime = Long.parseLong(speedAndBufferTimeArr[2]);
        long bufferTime = Long.parseLong(speedAndBufferTimeArr[3]);
        times[0] = (0 - windowTime) * 1000;
        times[1] = (0 - windowTime - Math.round(length / carSpeed) * 60 + bufferTime) * 1000;
        times[2] = (0 - windowTime - Math.round(length / footSpeed) * 60 - bufferTime) * 1000;
        return times;
    }

    /**
     * 获取配置的窗口时间
     *
     * @return 窗口时间
     */
    public long getWindowTime() {
        String speedAndTime = warnConfiguration.speedAndTime;
        String[] speedAndBufferTimeArr = speedAndTime.split(",");
        return 0 - Long.parseLong(speedAndBufferTimeArr[2]);
    }

    public static void main(String[] args) {
        GeometryFactory geometryFactory = new GeometryFactory();
        WKTReader wktReader = new WKTReader(geometryFactory);
        String subway = "LINESTRING(113.564679 34.795915,113.562354 34.814902)";
        LineString lineString = null;
        try {
            lineString = (LineString) wktReader.read(subway);
            System.out.println("LineString: " + lineString + "; LineLength: " + (lineString.getLength() * 111.265));
            System.out.println(getPointDistance("113.564679 34.795915", "113.562354 34.814902") * 111.265);
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}
